﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.MathLib
{

    /// <summary>
    /// 回转体
    /// </summary>
    public class Revolve3d : Solid3d
    {
        private PlanarSurface3d profile;
        private Vector3 origin;
        private Vector3 axis;
        private double startAngle;
        private double endAngle;
        private bool isClosed;

        public PlanarSurface3d Profile { get => profile; set => SetSize(value, origin, axis, startAngle, endAngle, isClosed); }
        public Vector3 Origin { get => axis; set => SetSize(profile, value, axis, startAngle, endAngle, isClosed); }
        public Vector3 Axis { get => axis; set => SetSize(profile, origin, value, startAngle, endAngle, isClosed); }
        public double StartAngle { get => startAngle; set => SetSize(profile, origin, axis, value, endAngle, isClosed); }
        public double EndAngle { get => endAngle; set => SetSize(profile, origin, axis, startAngle, value, isClosed); }
        public bool IsClosed { get => isClosed; set => SetSize(profile, origin,axis, startAngle, endAngle, value); }

        public static int TempSegments = 50;

        public Revolve3d() { }

        public Revolve3d(PlanarSurface3d profile, Vector3 origin, Vector3 axis, double startAngle, double endAngle, bool isClosed = true)
        {
            this.SetSize(profile, origin, axis, startAngle, endAngle, isClosed);
        }

        public Surface3d[] Surfaces;
        private TopoFaceModel topoFaceModel;
        public Revolve3d SetSize(PlanarSurface3d profile, Vector3 origin, Vector3 axis, double startAngle, double endAngle, bool isClosed = true)
        {
            if (topoFaceModel != null && (this.profile != profile || 
                                          this.origin != origin || 
                                          this.axis != axis ||
                                          this.startAngle != startAngle || 
                                          this.endAngle != endAngle || 
                                          this.isClosed != isClosed))
            {
                topoFaceModel = null;
            }
            this.profile = profile;
            this.origin = origin;
            this.axis = axis;
            this.startAngle = startAngle;
            this.endAngle = endAngle;
            this.isClosed = isClosed;
            return this;
        }

        public override TopoFaceModel CreateTopoModel()
        {
            if (topoFaceModel != null)
                return topoFaceModel;

            var surfaces = new List<Surface3d>();
            foreach (var loop in profile.OuterLoop)
            {
                var revolvedSurface = new RevolvedSurface3d(loop, origin, axis, startAngle, endAngle);
                surfaces.Add(revolvedSurface);
            }

            if (isClosed)
            {
                surfaces.Add(GeneratesPlanarSurface(origin, axis, startAngle));
                var face = GeneratesPlanarSurface(origin, axis, endAngle);
                face.Normal.Negate();
                surfaces.Add(face);

            }
            this.Surfaces = surfaces.ToArray();
            this.topoFaceModel = new TopoFaceModel() { Surfaces = this.Surfaces.ToListEx() };

            return this.topoFaceModel;
        }

        private PlanarSurface3d GeneratesPlanarSurface(Vector3 origin, Vector3 axis, double angle)
        {
            var plane = profile.Plane.Clone();
            var mat = new Matrix4().MakeRotationAxis(axis, angle);
            plane.ApplyMatrix4(mat);

            var outloop = new List<Curve3d>();
            foreach (var loop in profile.OuterLoop)
            {
                outloop.Add(loop.Clone().RotateRoundAxis(origin, axis, angle));
            }

            return new PlanarSurface3d(plane, outloop);
        }

        public override Solid3d CreateMesh()
        {
            #region 注释
            //base.Mesh();

            //this.Geometry.Groups = new GeometryGroup[1]
            //{
            //    new GeometryGroup{ Name = "Geometry", Start = 0, Count = this.Geometry.Indics.Length, MaterialIndex = 0 },
            //};

            //this.Edge = new GeometryData();

            //double angle = this.EndAngle - this.StartAngle;
            //double angleDiv = angle / Revolve3d.TempSegments;
            //var allPoints = new ListEx<Vector3>();
            //var indices = new ListEx<int>();
            //foreach (var loop in this.Profile.OuterLoop)
            //{
            //    var points = loop.GetPoints();
            //    for (int i = 0; i < points.Count; i++)
            //    {
            //        int nxi = (i + 1) % points.Count;
            //        for (int j = 0; j < Revolve3d.TempSegments; j++)
            //        {
            //            //var nxj = (j + 1) % points.Count;
            //            var p1 = points[i].Clone().RotateRoundAxis(new Vector3(), this.Axis, j * angleDiv);
            //            var p2 = points[nxi].Clone().RotateRoundAxis(new Vector3(), this.Axis, j * angleDiv);
            //            //var p3 = points[i].Clone().RotateRoundAxis(new Vector3(), this.Axis, nxj * angleDiv);
            //            //var p4 = points[nxi].Clone().RotateRoundAxis(new Vector3(), this.Axis, nxj * angleDiv);

            //            var count = allPoints.Count;
            //            indices.Push(count, count + 1);
            //            allPoints.Push(p1, p2);

            //        }
            //    }
            //}

            //this.Edge.Verteics = Utils.GenerateVertexArr(allPoints);
            //this.Edge.Indics = indices.ToArray();
            //return this;
            #endregion
            base.CreateMesh();
            base.MeshOneMaterial(this.Surfaces);
            return this;
        }
    }
}
